﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using RuYiAdmin.Net.Common.CommonClass.CaptchaPicture;
using RuYiAdmin.Net.Common.Global;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RuYiAdmin.Net.Common.Utility
{
    /// <summary>
    /// 验证码工具类
    /// </summary>
    public class RuYiCaptchaUtil
    {
        /// <summary>
        /// 生产验证码
        /// </summary>
        /// <returns></returns>
        public static Captcha GenerateCaptcha()
        {
            var captcha = new Captcha();

            captcha.Id = Guid.NewGuid();

            var oper = GetOperator();

            var arr = GetNumber(oper);

            var firstNum = arr[0];
            var secondNum = arr[1];

            var resultNum = GetResult(firstNum, secondNum, oper);

            var strCode = firstNum.ToString() + oper + secondNum.ToString() + "=";

            captcha.CaptchaPicture = CreateImg(strCode);

            RuYiRedisContext.Set(captcha.Id.ToString(), resultNum, RuYiAdminGlobalContext.JwtSettings.SaltExpiration);

            return captcha;
        }

        /// <summary>
        /// 随机获取运算符
        /// </summary>
        /// <returns></returns>
        private static string GetOperator()
        {
            string OperatorArray = "+,-,×,÷";
            String[] VcArray = OperatorArray.Split(',');
            Random random = new Random();
            int iNum = random.Next(VcArray.Length);
            return VcArray[iNum];
        }

        /// <summary>
        /// 随机获取数并添加到数组
        /// </summary>
        /// <returns></returns>
        private static int[] GetNumber(string oper)
        {
            int[] numList = new int[2];
            string OperatorArray = "1,2,3,4,5,6,7,8,9,10";
            String[] VcArray = OperatorArray.Split(',');
            Random random = new Random();
            int iNum = random.Next(VcArray.Length);
            int iNum1 = random.Next(VcArray.Length);
            if (oper == "-" || oper == "÷")
            {
                numList[0] = Convert.ToInt32(VcArray[iNum]);
                numList[1] = Convert.ToInt32(VcArray[iNum1]);
                if (oper == "÷")
                {
                    while (true)
                    {
                        //必须整除
                        if (numList[0] > numList[1] && numList[0] % numList[1] == 0)
                        {
                            break;
                        }

                        iNum = random.Next(VcArray.Length);
                        iNum1 = random.Next(VcArray.Length);

                        numList[0] = Convert.ToInt32(VcArray[iNum]);
                        numList[1] = Convert.ToInt32(VcArray[iNum1]);
                    }
                }
            }
            else
            {
                numList[0] = Convert.ToInt32(VcArray[iNum]);
                numList[1] = Convert.ToInt32(VcArray[iNum1]);
            }
            return numList;
        }

        /// <summary>
        /// 获取运算结果
        /// </summary>
        /// <param name="firstNum"></param>
        /// <param name="secondNum"></param>
        /// <param name="oper"></param>
        /// <returns></returns>
        private static int GetResult(int firstNum, int secondNum, string oper)
        {
            int result = 0;
            switch (oper)
            {
                case "+":
                    result = firstNum + secondNum;
                    break;
                case "-":
                    result = firstNum - secondNum;
                    break;
                case "×":
                    result = firstNum * secondNum;
                    break;
                case "÷":
                    result = firstNum / secondNum;
                    break;
            }
            return result;
        }

        /// <summary>
        /// 生成图象
        /// </summary>
        /// <param name="strCode">随机数</param>
        private static String CreateImg(string strCode)
        {
            var width = 60;
            var height = 25;

            //颜色列表，用于验证码、噪线、噪点 
            Color[] Colors = { Color.Black, Color.Red, Color.DarkBlue, Color.DarkCyan, Color.Purple };

            using var image = new Image<Rgba32>(width, height);
            {
                // 字体
                var fonts = new FontCollection();
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Library/Fonts/RadioCanada-Bold.ttf");
                FontFamily font1 = fonts.Add(path);
                var font = font1.CreateFont(18, FontStyle.Regular);

                //画图片的前景噪音点
                Random r = new Random();

                image.Mutate(ctx =>
                {
                    // 白底背景
                    ctx.BackgroundColor(Color.White);

                    // 画验证码
                    for (int i = 0; i < strCode.Length; i++)
                    {
                        int x = 10 * i + 3;
                        ctx.DrawText(strCode[i].ToString()
                            , font
                            , Colors[r.Next(Colors.Length)]
                            , new PointF(x, r.Next(-3, 3)));
                    }

                    // 画干扰线
                    for (int i = 0; i < 10; i++)
                    {
                        var pen = new Pen(Colors[r.Next(Colors.Length)], 0.2f);
                        var p1 = new PointF(r.Next(width), r.Next(height));
                        var p2 = new PointF(r.Next(width), r.Next(height));

                        ctx.DrawLines(pen, p1, p2);
                    }

                    // 画噪点
                    for (int i = 0; i < 80; i++)
                    {
                        var pen = new Pen(Colors[r.Next(Colors.Length)], r.Next(1, 2));
                        var p1 = new PointF(r.Next(width), r.Next(height));
                        var p2 = new PointF(p1.X + 1f, p1.Y + 1f);

                        ctx.DrawLines(pen, p1, p2);
                    }

                });

                return image.ToBase64String(SixLabors.ImageSharp.Formats.Gif.GifFormat.Instance);
            }
        }
    }
}
